#include "thread.h"
#include <stdlib.h>
#include <pthread.h>
#include <sched.h>
#include <unistd.h>

typedef struct _thread_node_t{
    pthread_t thd;
    void *(*end_routine)();
    struct _thread_node_t *next;
} thread_node_t;

static thread_node_t *threads;

void prepare_threads(){
    threads = NULL;
}
int create_and_run_thread(void *(*start_routine)(void *), void *arg, void *(*end_routine)()){
    thread_node_t *rover;
    thread_node_t *thd;

    if(start_routine == NULL){return 1;}

    thd = malloc(sizeof(thread_node_t));
    if(thd == NULL){return 1;}
    int ret = pthread_create(&thd->thd, NULL, start_routine, (void*) arg);
    thd->next = NULL;
    thd->end_routine = end_routine;
    if(ret){
        goto pthread_error;
    }
    if(threads == NULL){
        threads = thd;
    }else{
        for(rover = threads; rover->next != NULL; rover = rover->next){;}
        rover->next = thd;
    }
    return ret;
pthread_error:
    if(thd != NULL){
        free(thd);
    }
    return ret;
}
void thread_yield(){
    sched_yield();
}
void thread_sleep(int microseconds){
    usleep(microseconds);
}
void close_threads(){
    thread_node_t *rover;

    for(rover = threads; rover != NULL; rover = rover->next){
        if(rover->end_routine != NULL){
            rover->end_routine();
        }
    }
    for(rover = threads; rover != NULL; rover = rover->next){
        pthread_join(rover->thd, NULL);
    }
}

mutex_t* create_mutex(){
    mutex_t *ret = malloc(sizeof(mutex_t));
    if(ret == NULL){return ret;}
    if(pthread_mutex_init(ret, NULL)){
        free(ret);
        ret = NULL;
    }
    return ret;
}

void mutex_lock(mutex_t *mt){
    pthread_mutex_lock(mt);
}

void mutex_unlock(mutex_t *mt){
    pthread_mutex_unlock(mt);
}

void mutex_cleanup(mutex_t **mt){
    if(mt != NULL){
        if(*mt != NULL){
            free(*mt);
        }
        *mt = NULL;
    }
}
